﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using MVVMCommon.Repositories;
using System.Threading.Tasks;
using System.Text;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Collections.Generic;
namespace FlashlightRecorder.Repositories
{
    public class SimpleRepository<TEntity> : IRepository<string, TEntity>
    {
        static System.Runtime.Serialization.Json.DataContractJsonSerializer _serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(TEntity));
        static TaskScheduler s = TaskScheduler.Default;

        static string _typepath = typeof(SimpleRepository<TEntity>).Name + "_" + typeof(TEntity).Name;
        string _path;
        static IsolatedStorageFile _localFolder = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication();
        volatile object _lock = new object();

        public static async Task<SimpleRepository<TEntity>> CreateSimpleRepositoryAsync(string instanceName)
        {
            var path = _typepath + "_" + Convert.ToBase64String(Encoding.UTF8.GetBytes(instanceName));
            if (!_localFolder.DirectoryExists(path))
            {
                _localFolder.CreateDirectory(path);
            }

            var instance = new SimpleRepository<TEntity>(path);
            return await TaskEx.FromResult(instance);
        }


        private SimpleRepository(string path)
        {
            _path = path;
        }


        public async Task<TEntity> GetByKeyAsync(string key)
        {
            var fileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(key));
            var filePath = System.IO.Path.Combine(_path, fileName);

            if (!_localFolder.FileExists(filePath))
            {


                return default(TEntity);
            }
            else
            {
                return await ReadEntityFromFileAsync(filePath);




            }


        }

        private static async Task<TEntity> ReadEntityFromFileAsync(string filePath)
        {
            TEntity rval;
            var ms = new MemoryStream();
            try
            {

            
            using (var strm = _localFolder.OpenFile(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                await strm.CopyToAsync(ms);
            }

            }
            catch (Exception ex)
            {

                throw;
            }
            ms.Position = 0;
            rval = (TEntity)_serializer.ReadObject(ms);
            return rval;
        }

        public async Task SetOrUpdateByKeyAsync(string key, TEntity entity)
        {

            var fileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(key));
            var filePath = System.IO.Path.Combine(_path, fileName);
            var ms = new MemoryStream();
            _serializer.WriteObject(ms, entity);
            ms.Position = 0;
            using (var strm = _localFolder.OpenFile(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                await ms.CopyToAsync(strm);
            }

        }

        public async Task<System.Collections.Generic.IDictionary<string, TEntity>> GetAllAsync()
        {
            Dictionary<string, TEntity> rval = new Dictionary<string, TEntity>();
            var files = _localFolder.GetFileNames(System.IO.Path.Combine(_path, "*"));

            var entities = files.Select
                  (
                      f =>
                      {
                          var buf = Convert.FromBase64String(System.IO.Path.GetFileName(f));
                          return new { File = f, Key = Encoding.UTF8.GetString(buf, 0, buf.Length) };
                      }
                  );
            foreach (var p in entities)
            {
                var entity = await ReadEntityFromFileAsync(System.IO.Path.Combine(_path,p.File));
                rval.Add(p.Key, entity);
            }



            return rval;

        }

        public Task<bool> RemoveAsync(string key)
        {
            var fileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(key));
            var filePath = System.IO.Path.Combine(_path, fileName);

            if (!_localFolder.FileExists(filePath))
            {
                return TaskEx.FromResult(false);
            }
            else
            {
                _localFolder.DeleteFile(filePath);
                return TaskEx.FromResult(false);
            }
        }
    }
}
